import {
	getRefreshToken,
	getAccessToken,
	setAccessToken
} from './auth.js'

// import {
// 	useUserStore
// } from './store'
import Request from '@/js_sdk/luch-request/luch-request/index.js'
import * as authApi from '@/api/auth'

const options = {
	// 显示操作成功消息 默认不显示
	showSuccess: false,
	// 成功提醒 默认使用后端返回值
	successMsg: '',
	// 显示失败消息 默认显示
	showError: true,
	// 失败提醒 默认使用后端返回信息
	errorMsg: '',
	// 显示请求时loading模态框 默认显示
	showLoading: true,
	// loading提醒文字
	loadingMsg: '加载中',
	// 需要授权才能请求 默认放开
	auth: false,
	// ...
}

// Loading全局实例
const LoadingInstance = {
	target: null,
	count: 0,
}

/**
 * 关闭loading
 */
function closeLoading() {
	if (LoadingInstance.count > 0) LoadingInstance.count--
	if (LoadingInstance.count === 0) uni.hideLoading()
}
/**
 * @description 请求基础配置 可直接使用访问自定义请求
 */
const http = new Request({
	// 请求基准地址
	baseURL: "https://your-backend-api-url.com/api",
	timeout: 8000,
	header: {
		Accept: '*/*',
		'Content-Type': 'application/json;charset=UTF-8'
	},
	// #ifdef APP-PLUS
	sslVerify: false,
	// #endif
	// #ifdef H5
	// 跨域请求时是否携带凭证（cookies）仅H5支持（HBuilderX 2.6.15+）
	withCredentials: false,
	// #endif
	custom: options,
})

/**
 * @description 请求拦截器
 */
http.interceptors.request.use(
	(config) => {
		// 自定义处理【loading 加载中】：如果需要显示 loading，则显示 loading
		if (config.custom.showLoading) {
			LoadingInstance.count++
			LoadingInstance.count === 1 &&
				uni.showLoading({
					title: config.custom.loadingMsg,
					mask: true,
					fail: () => {
						uni.hideLoading()
					},
				})
		}
		// 添加 token 请求头标识
		const token = getAccessToken()
		if (token) {
			config.header.Authorization = `Bearer ${token}`
		}
		return config
	},
	(error) => {
		return Promise.reject(error)
	},
)

/**
 * @description 响应拦截器
 */
http.interceptors.response.use(
	(response) => {
		// 自定处理【loading 加载中】：如果需要显示 loading，则关闭 loading
		response.config.custom.showLoading && closeLoading()
		// 返回结果：包括 code + data + msg
		const resData = response.data
		const code = resData.code
		if (code === 200) {
			return Promise.resolve(response.data)
		} else if (code === 401) {
			return refreshToken(response.config)
		} else {
			uni.showToast({
				title: resData.message || '出错啦！',
				icon: 'none',
				mask: true,
			})
		}
	},
	(error) => {
		let errorMessage = '网络请求出错'
		if (error !== undefined) {
			switch (error.statusCode) {
				case 400:
					errorMessage = '请求错误'
					break
				case 401:
					errorMessage = '请登录'
					// 正常情况下，后端不会返回 401 错误，所以这里不处理 handleAuthorized
					break
				case 403:
					errorMessage = '拒绝访问'
					break
				case 404:
					errorMessage = '请求出错'
					break
				case 408:
					errorMessage = '请求超时'
					break
				case 429:
					errorMessage = '请求频繁, 请稍后再访问'
					break
				case 500:
					errorMessage = '服务器开小差啦,请稍后再试~'
					break
				case 501:
					errorMessage = '服务未实现'
					break
				case 502:
					errorMessage = '网络错误'
					break
				case 503:
					errorMessage = '服务不可用'
					break
				case 504:
					errorMessage = '网络超时'
					break
				case 505:
					errorMessage = 'HTTP 版本不受支持'
					break
			}
			if (error.errMsg.includes('timeout')) errorMessage = '请求超时'
			// #ifdef H5
			if (error.errMsg.includes('Network'))
				errorMessage = window.navigator.onLine ? '服务器异常' : '请检查您的网络连接'
			// #endif
		}

		if (error && error.config) {
			if (error.config.custom.showError === false) {
				uni.showToast({
					title: error.data?.msg || errorMessage,
					icon: 'none',
					mask: true,
				})
			}
			error.config.custom.showLoading && closeLoading()
		}

		return false
	},
)

// Axios 无感知刷新令牌，参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
let requestList = [] // 请求队列
let isRefreshToken = false // 是否正在刷新中
const refreshToken = async (config) => {
	// 如果当前已经是 refresh-token 的 URL 地址，并且还是 401 错误，说明是刷新令牌失败了，直接返回 Promise.reject(error)
	if (config.url.indexOf('/auth/refresh-token') >= 0) {
		isRefreshToken = false
		uni.navigateTo({
			url: '/pages/login/index'
		})
		return Promise.reject(new Error('error'))
	}

	console.log('过期', config)
	// 如果未认证，并且未进行刷新令牌，说明可能是访问令牌过期了
	if (!isRefreshToken) {
		isRefreshToken = true
		// 1. 如果获取不到刷新令牌，则只能执行登出操作
		const refreshToken = getRefreshToken()
		if (!refreshToken) {
			return handleAuthorized()
		}
		// 2. 进行刷新访问令牌
		const refreshTokenData = reactive({
			refreshToken: getRefreshToken(),
			clientId: 'https://your-backend-api-url.com/api',
		})
		const res = await authApi.refreshToken(refreshTokenData)
		console.log(res)
		setAccessToken(res.data.accessToken)
		try {
			// 2.1 刷新成功，则回放队列的请求 + 当前请求
			config.header.Authorization = 'Bearer ' + getAccessToken()
			requestList.forEach((cb) => {
				cb()
			})
			requestList = []
			return request(config)
		} catch (e) {
			// 为什么需要 catch 异常呢？刷新失败时，请求因为 Promise.reject 触发异常。
			// 2.2 刷新失败，只回放队列的请求
			requestList.forEach((cb) => {
				cb()
			})
			// 提示是否要登出。即不回放当前请求！不然会形成递归
			return handleAuthorized()
		} finally {
			requestList = []
			isRefreshToken = false
		}
	} else {
		// 添加到队列，等待刷新获取到新的令牌
		return new Promise((resolve) => {
			console.log('重试', config)
			requestList.push(() => {
				config.header.Authorization = 'Bearer ' +
					getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
				resolve(request(config))
			})
		})
	}
}

/**
 * 处理 401 未登录的错误
 */
const handleAuthorized = () => {
	const userStore = useUserStore()
	userStore.userLogout()
	isRefreshToken = false
	// 是否进入登录页
	uni.showModal({
		title: '提示',
		content: '重新登录？',
		success: function(res) {
			if (res.confirm) {
				uni.navigateTo({
					url: '/pages/login/index'
				})
			}
		},
	})

	// 登录超时
	return new Promise((resolve, reject) => {
		const res = {
			code: 401,
			message: '请重新登录',
			data: false,
		}
		reject(res)
	})
}

const request = (config) => {
	return http.middleware(config)
}

export default request